#pragma once
#include <boost/ptr_container/ptr_vector.hpp>
#include "Typedefs.hpp"
#include "TileWalker.hpp"
#include "MapFwd.hpp"
#include "ImportExport.hpp"

namespace Ogre
{
	class Vector3;
	class Ray;
} /*Ogre*/

namespace he
{
	class TerrainTile;

	//! Map implementation.
	class Map
	{
		// Attributes
	private:
		//! Map width.
		unsigned short const m_Width;
		//! Map height.
		unsigned short const m_Height;
		//! Map type.
		std::string const m_MapType;
		//! Array of tiles.
		TerrainTile **m_Tiles;

		// Operations
	public:
		//! Get map width.
		HE_ENGINE_API unsigned short get_width() const;
		//! Get map height.
		HE_ENGINE_API unsigned short get_height() const;
		//! Get tile.
		HE_ENGINE_API TerrainTile &get_tile(unsigned short X, unsigned short Y) const;
		//! Get neighbor tile in given direction.
		HE_ENGINE_API TerrainTile *get_neighbor(TerrainTile const &Tile, TileWalker::Direction Direction) const;
		//! Get the all neighbors.
		/*!
			The tiles are returned in this order: NORTH, NORTH-EAST, EAST, SOUTH-EAST, SOUTH, SOUTH-WEST, WEST, NORTH-WEST.
		*/
		HE_ENGINE_API void get_all_neighbors(TerrainTile const &Tile, TileContainer_t &Container) const;
		//! Get all neighbors in selected range.
		HE_ENGINE_API void get_all_neighbors(TerrainTile const &Tile, unsigned char Size, TileContainer_t &Container) const;
		//! Get all outline neighbors.
		/*!
			This functions returns all tiles that are neighbors of the tiles which create the outline of the "diamond" formed by the base tile and Size.
		*/
		HE_ENGINE_API void get_all_outline_neighbors(TerrainTile const &Tile, unsigned char Size, TileContainer_t &Container) const;
		//! Set tile deep.
		HE_ENGINE_API void set_tile_deep(TerrainTile const &Tile, char Deep, unsigned char Size, float Ratio);
		//! Set tile terrain type.
		HE_ENGINE_API void set_tile_terrain_type(TerrainTile &Tile, unsigned short TerrainType);
		//! Get the map type.
		std::string const &get_map_type() const;
		//! Export map to stream.
		HE_ENGINE_API void export_map(std::ostream &Stream) const;
		//! Create map.
		HE_ENGINE_API static MapPtr_t create_map(unsigned short Width, unsigned short Height, std::string const &MapType = "summer");
		//! Create map from file.
		HE_ENGINE_API static MapPtr_t create_map(std::istream &Stream);
	private:
		//! Create tiles.
		void create_tiles();
		//! Load default tiles.
		void load_default();
		//! Deep function.
		static float deep_func(float X1, float X2, float Ratio, float Deep);

		// Construction/Destruction
	private:
		//! Create default map.
		HE_ENGINE_API Map(unsigned short Width, unsigned short Height, std::string const &MapType);
	public:
		HE_ENGINE_API ~Map();
	};

	inline std::string const &Map::get_map_type() const
	{
		return m_MapType;
	}
}